<!--
 * @Descripttion: 资源文件选择器
 * @version: 1.0
 * @Author: sakuya
 * @Date: 2021年10月11日16:01:40
 * @LastEditors:
 * @LastEditTime:
-->

<template>
	<div class="sc-file-select">
		<div class="sc-file-select__side" v-loading="menuLoading || uploading===true">
			<div class="sc-file-select__side-menu">
				<el-tree ref="group" class="menu" node-key="id" :data="group" :current-node-key="''" :props="treeProps"
						 :highlight-current="true" :expand-on-click-node="false" default-expand-all @node-click="groupClick"
						 >
					<template #default="{ node,data }">
						<span class="custom-tree-node el-tree-node__label">
							<span><el-icon class="icon"><el-icon-folder/></el-icon>{{node.label}}</span>
							<span class="do">
								<el-icon @click.stop="showCatePop('add',node, data)"><el-icon-plus/></el-icon>
								<el-icon @click.stop="showCatePop('edit',node, data)" v-if="data.id !== rootCategory.id"><el-icon-edit/></el-icon>
								<el-icon @click.stop="delCate(node, data)" v-if="data.id !== rootCategory.id"><el-icon-delete/></el-icon>
							</span>
						</span>
					</template>
				</el-tree>
			</div>
			<div class="sc-file-select__side-msg" v-if="multiple">
				已选择 <b>{{value.length}}</b> / <b>{{max}}</b> 项
			</div>
		</div>
		<div class="sc-file-select__files" v-loading="listLoading">
			<div class="sc-file-select__top">
				<div class="upload" v-if="!hideUpload && mode === 1">
					<el-upload class="sc-file-select__upload" :disabled="group.length < 1" v-if="!uploading" action="" multiple :show-file-list="false"
							   :accept="accept" :on-change="uploadChange" :auto-upload="false">
						<el-button type="primary" icon="el-icon-upload" :disabled="group.length < 1">本地上传</el-button>
					</el-upload>
					<el-upload v-else class="sc-file-select__upload" disabled :auto-upload="false">
						<el-button type="primary" icon="el-icon-upload" disabled>上传中...</el-button>
					</el-upload>
					<span class="tips" v-if="group.length > 0"><el-icon><el-icon-warning/></el-icon>大小不超过{{maxSize}}MB</span>
					<span class="tips" v-else style="color: #F00;"><el-icon><el-icon-error/></el-icon>获取目录失败，请联系管理员</span>
				</div>
				<div class="operationMode" v-if="mode === 1">
					<el-button style="margin-left: 5px;" @click="modeChange" :disabled="data.length<=0 || uploading===true">批量操作</el-button>
				</div>
				<div class="operationMode2" v-if="mode === 2">
					管理文件：
					<el-button type="danger" :disabled="value.length<=0" @click="operationMode('del')">删 除</el-button>
					<el-button type="warning" :disabled="value.length<=0" @click="operationMode('move')">移 动</el-button>
					<el-button @click="modeChange">返回</el-button>
				</div>
				<div class="keyword">
					<el-input v-model="keyword" prefix-icon="el-icon-search" placeholder="文件名搜索" clearable
							  @keyup.enter="search" @clear="search"></el-input>
				</div>
			</div>
			<div class="sc-file-select__list">
				<el-scrollbar ref="scrollbar">
					<el-empty v-if="fileList.length===0 && data.length===0" description="无数据" :image-size="80"></el-empty>
					<div v-for="(file, index) in fileList" :key="index" class="sc-file-select__item">
						<div class="sc-file-select__item__file">
							<div class="sc-file-select__item__upload" v-if="!file.error">
								<el-progress type="circle" :percentage="file.progress" :width="70"></el-progress>
							</div>
							<div v-if="file.error" style="display: flex;align-items: center;justify-content: center;height: 100%;color: #F00;font-size:36px;">
								<el-tooltip
									:content="file.error"
									placement="top"
								>
								<el-icon>
									<el-icon-warning-filled />
								</el-icon>
								</el-tooltip>
							</div>
							<div v-else style="height: 100%;">
								<el-image :src="file.tempImg" fit="contain" v-if="_isImg(file.name)"></el-image>
								<div v-else style="display:flex;align-items:center;justify-content: center;height:100%;font-size:36px;">
									<el-icon>
										<el-icon-document />
									</el-icon>
								</div>
							</div>
						</div>
						<p>{{file.name}}</p>
					</div>
					<div v-for="item in data" :key="item[fileProps.key]" class="sc-file-select__item"
						 :class="{active: value.includes(item[fileProps.url]) }" @click="select(item)">
						<div class="sc-file-select__item__file">
							<div class="sc-file-select__item__checkbox" v-if="multiple || mode === 2">
								<el-icon>
									<el-icon-check/>
								</el-icon>
							</div>
							<div class="sc-file-select__item__select" v-else>
								<el-icon>
									<el-icon-check/>
								</el-icon>
							</div>
							<div class="sc-file-select__item__box"></div>
							<el-image v-if="_isImg(item[fileProps.url])" :src="showImage(item)" fit="contain" lazy></el-image>
							<div v-else class="item-file item-file-doc">
								<el-icon>
									<component :is="item.icon || 'sc-icon-doctype-unknown'"/>
								</el-icon>
							</div>
						</div>
						<p :title="item[fileProps.fileName]">{{item[fileProps.fileName]}}</p>
					</div>
				</el-scrollbar>
			</div>
			<div class="sc-file-select__pagination">
				<el-pagination small background layout="prev, pager, next" :total="total" :page-size="pageSize"
							   v-model:currentPage="currentPage" @current-change="reload"></el-pagination>
			</div>
			<div class="sc-file-select__do">
				<slot name="do"></slot>
				<el-button type="primary" :disabled="value.length<=0 || mode === 2" @click="submit">确 定</el-button>
			</div>
		</div>
	</div>
	<el-dialog :title="catePopTitle" v-model="catePopVisible" width="30%" destroy-on-close @close="catePopClose">
		<el-form :model="cateForm" ref="dialogForm" label-width="80px"
				 label-position="left">
			<el-form-item label="上级目录" prop="avatar">
				<el-cascader clearable style="width: 100%;"
							 v-model="cateForm.parent_id"
							 :options="group"
							 :props="{
								value: 'id',
								emitPath:true,
								checkStrictly:true,
								label: 'group_name'
							 }"
				></el-cascader>
			</el-form-item>
			<el-form-item label="目录名" prop="avatar">
				<el-input v-model="cateForm.name" placeholder="请输入目录名" clearable></el-input>
			</el-form-item>
		</el-form>
		<template #footer>
			<el-button @click="catePopVisible=false">取 消</el-button>
			<el-button type="primary" @click="catePopSubmit()">保 存
			</el-button>
		</template>
	</el-dialog>
	<el-dialog title="请选择新的目录" v-model="operationPopVisible" width="30%" destroy-on-close :close-on-click-modal="false"
			   :close-on-press-escape="false">
		<el-form label-width="80px" label-position="left" v-loading="operationPopLoading">
			<el-form-item label="目录" prop="avatar">
				<el-cascader clearable style="width: 100%;"
							 v-model="newCategoryId"
							 :options="group"
							 :props="{
								value: 'id',
								emitPath:true,
								checkStrictly:true,
								label: 'group_name'
							 }"
				></el-cascader>
			</el-form-item>
		</el-form>
		<template #footer>
			<el-button @click="operationPopVisible=false">取 消</el-button>
			<el-button type="primary" @click="coperationPopSubmit()" :loading="operationPopLoading">移 动
			</el-button>
		</template>
	</el-dialog>
</template>

<script>
import config from './config'
import { ElMessageBox } from 'element-plus'
import { uploadFile } from '@/utils/chunkUpload.js'
import api from '@/api/index.js'
import tool from '@/utils/tool.js'

export default {
  props: {
    modelValue: null,
    // fileType:1,//1是全部 2是仅图片 3是音频 4是视频 5文件
    fileType: { type: Number, default: 1 },
    hideUpload: { type: Boolean, default: false },
    multiple: { type: Boolean, default: false },
    max: { type: Number, default: config.max },
    onlyImage: { type: Boolean, default: false },
    maxSize: { type: Number, default: config.maxSize }
  },
  data () {
    return {
      mode: 1,
      cateForm: {
        id: '',
        name: '',
        parent_id: ''
      },
      catePopVisible: false,
      catePopMode: '',
      catePopTitles: {
        add: '新增',
        edit: '编辑'
      },
      showGrouploading: false,
      operationPopVisible: false,
      rootCategory: {},
      newCategoryId: [],
      groupFilterText: '',
      group: [],
      keyword: '',
      pageSize: 20,
      total: 0,
      currentPage: 1,
      data: [],
      menu: [],
      menuId: '',
      acceptList: [
        { type: 1, accept: '' },
        { type: 2, accept: 'image/gif, image/jpeg, image/png' },
        { type: 3, accept: 'audio/*' },
        { type: 4, accept: 'video/*' },
        { type: 5, accept: '.pdf, .doc, .docx, .xls, .xlsx' }
      ],
      // value: this.multiple ? [] : '',
      value: [],
      fileList: [],
      accept: '',
      // accept: this.onlyImage ? "image/gif, image/jpeg, image/png" : "",
      listLoading: false,
      menuLoading: false,
      treeProps: config.menuProps,
      fileProps: config.fileProps,
      files: config.files,
      returnData: [], // 返回的数据，items 整个数据返回，外部组件自行处理
      multipleDefault: false,
      operationPopLoading: false,
      uploading: false,
      apiObj: {
        attachmentGroup: api.system.attachmentGroup,
        attachment: api.system.attachment
      }
    }
  },
  watch: {
    multiple () {
      this.value = []
      this.$emit('update:modelValue', JSON.parse(JSON.stringify(this.value)))
    }
  },

  mounted () {
    // this.getMenu()
    this.getData()
    this.getGroup()
    this.multipleDefault = this.multiple
  },
  computed: {
    catePopTitle () {
      return this.catePopTitles[this.catePopMode] + '目录'
    }
  },
  methods: {
    showCatePop (type, node, data) {
      this.catePopMode = type
      console.log(type, node, data)
      if (type === 'edit') {
        this.cateForm.id = data.id
        this.cateForm.name = data.group_name
        this.cateForm.parent_id = data.parent_id
      }
      if (type === 'add') {
        this.cateForm.parent_id = data.id
      }
      this.catePopVisible = true
    },
    catePopClose () {
      this.cateForm.name = ''
      this.cateForm.parent_id = this.rootCategory.id
    },
    async delCate (node, data) {
      const that = this
      ElMessageBox.confirm('确认删除《' + data.group_name + '》目录吗？', '提醒').then(async () => {
        console.log('删除', data)
        const res = await this.apiObj.attachmentGroup.delete({ ids: data.id })
        this.showResMessage(res, function () {
          that.catePopVisible = false
          that.getGroup()
        }, '删除成功')
      })
    },
    showResMessage (res, successFun = () => {}, successMsg = '') {
      if (res.code === 0) {
        if (!successMsg) {
          successMsg = res.message
        }
        this.$message.success(successMsg)
        if (tool.isFunction(successFun)) {
          successFun(res)
        }
      } else {
        this.$message.error(res.message ?? '未知错误')
      }
    },
    getAccept () {
      this.accept = this.acceptList.filter(f => f.type == this.fileType)[0].accept
    },
    async getGroup () {
      this.showGrouploading = true
      const res = await this.apiObj.attachmentGroup.list()
      this.showGrouploading = false
      const newDatas = res.data
      newDatas.unshift({ id: 0, group_name: '全部' })
      console.log('newDatas', newDatas)
      this.group = tool.deepTree(newDatas, 'parent_id')
      /* this.group = res.data.map(item => {
				// item.parent_id = '0';
				return item;
			}); */
      if (this.group.length > 0) {
        this.rootCategory = this.group[0]
      }
      this.getAccept()
    },
    // 获取目录数据
    async getMenu () {
      this.menuLoading = true
      const res = await config.menuApiObj.list()
      this.menu = res.data
      this.menuLoading = false
    },
    // 获取列表数据
    async getData () {
      this.listLoading = true
      const reqData = {
        [config.request.menuKey]: this.menuId,
        [config.request.page]: this.currentPage,
        [config.request.pageSize]: this.pageSize,
        [config.request.keyword]: this.keyword
      }
      if (this.onlyImage) {
        reqData.type = 'image'
      }
      if (reqData[config.request.menuKey] === '0') {
        reqData[config.request.menuKey] = ''
      }
      const res = await config.listApiObj.page(reqData)
      const parseData = config.listParseData(res)
      console.log(parseData)
      this.data = parseData.rows
      this.total = parseData.total
      this.listLoading = false
      this.$refs.scrollbar.setScrollTop(0)
    },
    // 树点击事件
    groupClick (data) {
      this.menuId = data.id
      this.currentPage = 1
      this.keyword = null
      // 点击树后，清空上传失败的文件
      this.fileList.length = 0
      this.getData()
    },
    // 分页刷新表格
    reload () {
      this.getData()
    },
    search () {
      this.currentPage = 1
      this.getData()
    },
    select (item) {
      const itemUrl = item[this.fileProps.url]
      if (this.multipleDefault) {
        if (this.value.includes(itemUrl)) {
          this.value.splice(this.value.findIndex(f => f == itemUrl), 1)
          this.returnData = this.returnData.filter(r => {
            return r[this.fileProps.url] !== itemUrl
          })
        } else {
          this.value.push(itemUrl)
          this.returnData.push(item)
        }
      } else {
        if (this.value.includes(itemUrl)) {
          this.value = []
          this.returnData = []
        } else {
          this.value = [itemUrl]
          this.returnData = [item]
        }
      }
    },
    async catePopSubmit () {
      if (Array.isArray(this.cateForm.parent_id)) {
        this.cateForm.parent_id = this.cateForm.parent_id[this.cateForm.parent_id.length - 1]
      }
      const postData = {
        group_name: this.cateForm.name,
        parent_id: this.cateForm.parent_id
      }
      if (this.catePopMode === 'edit') {
        postData.id = this.cateForm.id
      }
      console.log(postData)
      const successMsg = this.catePopMode === 'edit' ? '编辑成功' : '新增成功'
      let res
      if (this.catePopMode === 'edit') {
        res = await this.apiObj.attachmentGroup.update(postData)
      } else {
        res = await this.apiObj.attachmentGroup.add(postData)
      }
      const that = this
      this.showResMessage(res, function () {
        that.catePopVisible = false
        that.getGroup()
      }, successMsg)
    },
    // 上传处理
    async uploadChange (file, fileList) {
      file.tempImg = URL.createObjectURL(file.raw)
      this.fileList = fileList

      const that = this
      setTimeout(() => {
        that.kaishi()
      }, 500)
    },
    async kaishi () {
      if (this.uploading) {
        return
      }
      this.uploading = true
      const that = this
      const tmpFileList = this.fileList.concat()
      for (let i = 0; i < tmpFileList.length; i++) {
        const file = tmpFileList[i]
        try {
          const res = await uploadFile(file.raw, {
            onProgress: (e) => {
              file.progress = e.jindu
            }
          })
          if (res.code !== 0) {
            if (res.code === 21001) {
              // 秒传成功
              file.progress = 100
              that.uploadSuccess(res, file.raw)
            } else {
              file.error = res.message
              that.uploadError(res)
            }
          } else {
            file.progress = 100
            that.uploadSuccess(res, file.raw)
          }
        } catch (e) {
          file.error = e.message
          that.uploadError(e.message)
        }
      }
      this.uploading = false
    },
    async uploadBefore (file) {
      console.log('uploadBefore ', file)
      const maxSize = file.size / 1024 / 1024 < this.maxSize
      if (!maxSize) {
        this.$message.warning(`上传文件大小不能超过 ${this.maxSize}MB!`)
        return false
      }
    },
    uploadSuccess (res, file) {
      const successCodes = [
        0,
        21001
      ]
      console.log('uploadSuccess ', res)
      if (!res) {
        return false
      }
      if (!successCodes.includes(res.code)) {
        this.$message.error(res.message)
        file.error = res.message
        return false
      }
      this.fileList.splice(this.fileList.findIndex(f => f.uid == file.uid), 1)
      // 如果是秒传的，需要判断是否在当前列表中
      if (res.code === 21001) {
        this.$message.success('秒传完成')

        const isExist = this.data.some(d => {
          return d[this.fileProps.url] === res.data[this.fileProps.url]
        })
        if (isExist) {
          return false
        }

        // 不存在，添加到列表
        this.data.unshift(res.data)

        return false
      }
      this.data.unshift(res.data)
    },
    uploadError (err) {
      this.$notify.error({
        title: '上传文件错误',
        message: err
      })
    },
    // 内置函数
    _isImg (fileUrl) {
      if (!fileUrl) {
        return ''
      }
      const imgExt = ['.jpg', '.jpeg', '.png', '.gif', '.bmp']
      const fileExt = fileUrl.substring(fileUrl.lastIndexOf('.'))
      return imgExt.indexOf(fileExt) != -1
    },
    _getExt (fileUrl) {
      if (!fileUrl) {
        return ''
      }
      return fileUrl.substring(fileUrl.lastIndexOf('.') + 1)
    },
    showImage (row) {
      return row[this.fileProps.baseUrl] + row[this.fileProps.url]
    },
    submit () {
      this.$emit('submit', this.returnData)
    },
    modeChange () {
      this.mode = this.mode === 1 ? 2 : 1
      if (this.mode === 2) {
        // 编辑模式，打开多选
        this.multipleDefault = true
      }
      if (this.mode === 1) {
        // 选择模式，恢复
        this.multipleDefault = this.multiple
      }
      this.value.length = 0
      this.returnData.length = 0
    },
    operationMode: async function (type) {
      console.log(type)
      const that = this
      if (type === 'del') {
        ElMessageBox.confirm('确认删除所选的文件吗？').then(async () => {
          that.listLoading = true
          const res = await that.apiObj.attachment.delete({ ids: that.returnData.map(item => item.id) })
          if (res.code === 0) {
            that.$message.success('删除成功')
          } else {
            that.$message.warning('删除失败')
          }
          that.getData()
        }).catch(() => {
        })
      }
      if (type === 'move') {
        that.operationPopVisible = true
      }
    },
    async coperationPopSubmit () {
      this.operationPopLoading = true
      const fileIds = this.returnData.map(item => { return item[this.fileProps.key] })
      const res = await this.apiObj.attachment.move({ ids: fileIds, group_id: this.newCategoryId[this.newCategoryId.length - 1] })
      this.operationPopLoading = false
      if (res.code === 0) {
        this.returnData = []
        this.returnData.length = 0
        this.$message.success('移动成功')
        this.reload()
        this.operationPopVisible = false
      } else {
        this.$message.error('移动失败')
      }
    }
  }
}
</script>

<style scoped>
.sc-file-select {
	display: flex;
}

.sc-file-select__files {
	flex: 1;
}

.sc-file-select__list {
	height: 500px;
}

.sc-file-select__item {
	display: inline-block;
	float: left;
	margin: 0 15px 25px 0;
	width: 110px;
	cursor: pointer;
}

.sc-file-select__item__file {
	width: 110px;
	height: 110px;
	position: relative;
}

.sc-file-select__item__file .el-image {
	width: 110px;
	height: 110px;
}

.sc-file-select__item__box {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	border: 2px solid var(--el-color-success);
	z-index: 1;
	display: none;
}

.sc-file-select__item__box::before {
	content: '';
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	background: var(--el-color-success);
	opacity: 0.2;
	display: none;
}

.sc-file-select__item:hover .sc-file-select__item__box {
	display: block;
}

.sc-file-select__item.active .sc-file-select__item__box {
	display: block;
}

.sc-file-select__item.active .sc-file-select__item__box::before {
	display: block;
}

.sc-file-select__item p {
	margin-top: 10px;
	white-space: nowrap;
	text-overflow: ellipsis;
	overflow: hidden;
	-webkit-text-overflow: ellipsis;
	text-align: center;
}

.sc-file-select__item__checkbox {
	position: absolute;
	width: 20px;
	height: 20px;
	top: 7px;
	right: 7px;
	z-index: 2;
	background: rgba(0, 0, 0, 0.2);
	border: 1px solid #fff;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

.sc-file-select__item__checkbox i {
	font-size: 14px;
	color: #fff;
	font-weight: bold;
	display: none;
}

.sc-file-select__item__select {
	position: absolute;
	width: 20px;
	height: 20px;
	top: 0px;
	right: 0px;
	z-index: 2;
	background: var(--el-color-success);
	display: none;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

.sc-file-select__item__select i {
	font-size: 14px;
	color: #fff;
	font-weight: bold;
}

.sc-file-select__item.active .sc-file-select__item__checkbox {
	background: var(--el-color-success);
}

.sc-file-select__item.active .sc-file-select__item__checkbox i {
	display: block;
}

.sc-file-select__item.active .sc-file-select__item__select {
	display: flex;
}

.sc-file-select__item__file .item-file {
	width: 110px;
	height: 110px;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

.sc-file-select__item__file .item-file i {
	font-size: 40px;
}

.sc-file-select__item__file .item-file.item-file-doc {
	color: #409eff;
}

.sc-file-select__item__upload {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	z-index: 1;
	background: rgba(255, 255, 255, 0.7);
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
}

.sc-file-select__side {
	width: 260px;
	margin-right: 15px;
	border-right: 1px solid rgba(128, 128, 128, 0.2);
	display: flex;
	flex-flow: column;
}

.sc-file-select__side-menu {
	flex: 1;
}

.sc-file-select__side-msg {
	height: 32px;
	line-height: 32px;
}

.sc-file-select__top {
	margin-bottom: 15px;
	display: flex;
	justify-content: space-between;
}

.sc-file-select__upload {
	display: inline-block;
}

.sc-file-select__top .tips {
	font-size: 12px;
	margin-left: 10px;
	color: #999;
}

.sc-file-select__top .tips i {
	font-size: 14px;
	margin-right: 5px;
	position: relative;
	bottom: -0.125em;
}

.sc-file-select__pagination {
	margin: 15px 0;
}

.sc-file-select__do {
	text-align: right;
}

.custom-tree-node {
	display: flex;
	flex: 1;
	align-items: center;
	justify-content: space-between;
	font-size: 14px;
	padding-right: 24px;
	height: 100%;
}

.custom-tree-node .label {
	display: flex;
	align-items: center;;
	height: 100%;
}

.custom-tree-node .do {display: none;}
.custom-tree-node .do i {margin-left: 10px;color: #999;}
.custom-tree-node .do i:hover {color: #333;}
.custom-tree-node:hover .do {display: inline-block;}
.footer {
	display: flex;
}
</style>
